﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SimpleChart.Kernel.Series;

namespace SimpleChart.Kernel.Painter
{
    class ChartAreaPainter
    {
        public void Draw(Graphics graphics, Chart chart, int width, int height)
        {
            graphics.FillRectangle(Brushes.White, new Rectangle(0, 0, width, height)); // background
            graphics.DrawRectangle(Pens.LightGray, new Rectangle(PainterParameters.MARGIN, PainterParameters.MARGIN, width - (PainterParameters.MARGIN) * 2, height - (PainterParameters.MARGIN * 2))); // border
            DrawTitle(graphics, chart.Title, width, height); // title
            DrawGridLines(graphics, width, height);
            DrawAxisXLabels(graphics, chart.AxisXMember, chart.Data, width, height);

            if (NeedDrawAxisYLabels(chart.SeriesCollection, AxisYType.Left))
            {
                DrawAxisY(graphics, chart.Data, chart.SeriesCollection, height, width, AxisYType.Left);
            }
            if (NeedDrawAxisYLabels(chart.SeriesCollection, AxisYType.Right))
            {
                DrawAxisY(graphics, chart.Data, chart.SeriesCollection, height, width, AxisYType.Right);
            }

            DraowLegends(graphics, chart.SeriesCollection, width, height);
        }

        private void DraowLegends(Graphics graphics, ICollection<SeriesBase> seriesCollection, int width, int height)
        {
            Brush brush = new SolidBrush(Color.Black);
            string fontName = SystemFonts.DefaultFont.FontFamily.Name;
            Font font = new Font(fontName, 12);

            StringFormat format = new StringFormat();
            format.Alignment = StringAlignment.Near;
            format.LineAlignment = StringAlignment.Center;

            int legendWidth = (width - PainterParameters.MARGIN * 2 - PainterParameters.AXIS_Y_WIDHT * 2) / seriesCollection.Count;
            int startX = PainterParameters.MARGIN + PainterParameters.AXIS_Y_WIDHT;
            int y = height - PainterParameters.MARGIN - PainterParameters.LEGEND_HEIGHT + 10;

            int i = 0;
            foreach (var item in seriesCollection)
            {
                int x = startX + legendWidth * i;
                graphics.FillRectangle(new SolidBrush(item.Color), new RectangleF { X = x, Y = y, Width = 30,Height = 16});
                graphics.DrawString(item.Name, font, brush, x + 30 + 5, y);

                i++;
            }
        }

        private void DrawAxisY(Graphics graphics, DataTable data, ICollection<SeriesBase> seriesCollection, int height,int width, AxisYType axisYType)
        {
            int labelRectHeight = 20;

            decimal ceiling = ChartHelper.GetAxisYCeiling(data,seriesCollection, axisYType); // 凑一个PainterParameters.AXIS_Y_LABLE_COUNT的整数倍数

            int startX = axisYType == AxisYType.Left ? PainterParameters.MARGIN : width - PainterParameters.MARGIN - PainterParameters.AXIS_Y_WIDHT;
            float startY = height - PainterParameters.MARGIN - PainterParameters.LEGEND_HEIGHT - PainterParameters.AXIS_X_HEIGHT - labelRectHeight / 2;

            Brush brush = new SolidBrush(Color.Black);
            string fontName = SystemFonts.DefaultFont.FontFamily.Name;
            Font font = new Font(fontName, 12);

            StringFormat format = new StringFormat();
            format.Alignment = axisYType == AxisYType.Left ? StringAlignment.Far : StringAlignment.Near;
            format.LineAlignment = StringAlignment.Center;

            int axislabelHeight = (height - PainterParameters.MARGIN * 2 - PainterParameters.TITLE_HEIGHT - PainterParameters.AXIS_X_HEIGHT - PainterParameters.LEGEND_HEIGHT) / PainterParameters.AXIS_Y_LABLE_COUNT;

            for (int i = 0; i <= PainterParameters.AXIS_Y_LABLE_COUNT; i++)
            {
                RectangleF rect = new RectangleF(startX, startY, PainterParameters.AXIS_Y_WIDHT, labelRectHeight);

                decimal tempDecimal = ceiling / 10 * i;
                string tempStr = tempDecimal.ToString();
                if (tempStr.Contains("."))
                {
                    tempStr = tempStr.TrimEnd('0');
                    tempStr = tempStr.TrimEnd('.');
                }

                if ((ceiling > 1000000000 || ceiling < 0.000001m) && tempStr != "0")
                {
                    tempStr = String.Format("{2}E{0}{1}", tempDecimal < 1 ? "-" : "+",
                        tempStr.Count(c => c == '0').ToString().PadLeft(2,'0'), 
                        tempDecimal > 1 ? tempStr.First().ToString() : tempStr.Last().ToString());
                }
                graphics.DrawString(tempStr, font, brush, rect, format);

                startY -= (axislabelHeight + 0.5f);
            }
        }

        private void DrawAxisXLabels(Graphics graphics, string valueMember, DataTable data, int width, int height)
        {
            int axisXWidth = width - PainterParameters.MARGIN * 2 - PainterParameters.AXIS_Y_WIDHT * 2;
            int axisXLableCount = data.Rows.Count;
            int axisXLableWidth = axisXWidth / axisXLableCount;

            Brush brush = new SolidBrush(Color.Black);
            string fontName = SystemFonts.DefaultFont.FontFamily.Name;
            Font font = new Font(fontName, 12);

            StringFormat format = new StringFormat();
            format.Alignment = StringAlignment.Center;
            format.LineAlignment = StringAlignment.Center;

            for (int i = 0; i < axisXLableCount; i++)
            {
                RectangleF rect = new RectangleF(PainterParameters.AXIS_Y_WIDHT + PainterParameters.MARGIN + axisXLableWidth * i, 
                    height - PainterParameters.MARGIN - PainterParameters.LEGEND_HEIGHT - PainterParameters.AXIS_X_HEIGHT, 
                    axisXLableWidth, 
                    PainterParameters.AXIS_X_HEIGHT);
                graphics.DrawString(data.Rows[i][valueMember].ToString(), font, brush, rect, format);
            }
        }

        private void DrawGridLines(Graphics graphics, int width, int height)
        {
            int gridHeight = height - PainterParameters.MARGIN * 2 - PainterParameters.TITLE_HEIGHT - PainterParameters.AXIS_X_HEIGHT - PainterParameters.LEGEND_HEIGHT;
            int gridWidth = width - (PainterParameters.MARGIN + PainterParameters.AXIS_Y_WIDHT) * 2;
            int startX = PainterParameters.MARGIN + PainterParameters.AXIS_Y_WIDHT;

            for (int i = 0; i < PainterParameters.AXIS_Y_LABLE_COUNT + 1; i++)
            {
                int startY = PainterParameters.MARGIN + PainterParameters.TITLE_HEIGHT + gridHeight * i / PainterParameters.AXIS_Y_LABLE_COUNT;
                graphics.DrawLine(Pens.LightGray, startX, startY, startX + gridWidth, startY);
            }
        }

        private void DrawTitle(Graphics graphics, string title, int width, int height)
        {
            Brush brush = new SolidBrush(Color.Black);
            string fontName = SystemFonts.DefaultFont.FontFamily.Name;
            Font font = new Font(fontName, 16, FontStyle.Bold);

            RectangleF rect = new RectangleF(0f, PainterParameters.MARGIN, width - PainterParameters.MARGIN * 2, PainterParameters.TITLE_HEIGHT);
            StringFormat format = new StringFormat();
            format.Alignment = StringAlignment.Center;
            format.LineAlignment = StringAlignment.Center;

            graphics.DrawString(title, font, brush, rect, format);
        }

        private bool NeedDrawAxisYLabels(ICollection<SeriesBase> seriesCollection, AxisYType axisType)
        {
            foreach (var item in seriesCollection)
            {
                if (item.AxisType == axisType)
                {
                    return true;
                }
            }
            return false;
        }
    }
}
